#include "Component/MissionComponent.h"
#include "GameFramework/Actor.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/SpringArmComponent.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/Pawn.h"
#include "Camera/PlayerCameraManager.h"
#include "UserWidget/WidgetComponent/SingleMarkerWidget.h"
#include "Actor/LandmarkMaster.h"
#include "UserWidget/WidgetComponent/CompassWidget.h"
#include "UserWidget/WidgetComponent/InMissionWidget.h"
#include "UserWidget/WidgetComponent/OnMissionFinishedWidget.h"
#include "UserWidget/WidgetComponent/TimerWidget.h"
#include "UserWidget/WidgetComponent/InteractionWidget.h"
#include "UserWidget/WidgetComponent/GlobalNotificationWidget.h"
#include "UserWidget/WidgetComponent/LocationObjectivesWidget.h"
#include "UserWidget/WidgetComponent/SaveGameWidget.h"
#include "UserWidget/WidgetComponent/PlayerLevelWidget.h"
#include "Engine/Engine.h"
#include "Blueprint/WidgetLayoutLibrary.h"
#include "Libraries/MissionSystemFL.h"
#include "Actor/TargetsManager.h"
#include "UserWidget/WidgetComponent/SingleDirectionWidget.h"
#include "UserWidget/WidgetComponent/SingleObjectiveWidget.h"
#include "Data/BaseData.h"
#include "TimerManager.h"
#include "GameFramework/Character.h"
#include "Components/SkeletalMeshComponent.h"
#include "Libraries/GameKitFL.h"
#include "GameFramework/GameModeBase.h"
#include "Engine/DataTable.h"
#include "Components/Image.h"
// #include "Libraries/CommonLibrary.h"

UMissionComponent::UMissionComponent()
{
	PrimaryComponentTick.bCanEverTick = true;
	MaximumCompassTranslation = 270.f;
	CurrentSequenceIndex = 0;
	UnitsPerMeter = 150.f;
	ElevationRange = 150.f;
	FollowMaxDistance = 2000.f;
	ScreenMarkerRadius = 500.f;
	ScreenMarkerMargin = 100.f;
	InteractionText.Add(ETargetType::QuestGiver, FText::FromString("Speak"));
	InteractionText.Add(ETargetType::Collectable, FText::FromString("Collect"));
	InteractionText.Add(ETargetType::Interactable, FText::FromString("Interact"));
	InteractionKey = FKey("E");
	Directions.Add(FDirections(FName(TEXT("N")),0));
	Directions.Add(FDirections(FName(TEXT("E")), 90));
	Directions.Add(FDirections(FName(TEXT("S")), 180));
	Directions.Add(FDirections(FName(TEXT("W")), -90));
	Directions.Add(FDirections(FName(TEXT("NE")), 45));
	Directions.Add(FDirections(FName(TEXT("SW")), -135));
	Directions.Add(FDirections(FName(TEXT("SE")), 135));
	Directions.Add(FDirections(FName(TEXT("NW")), -45));
}

void UMissionComponent::PostInitProperties() {
	Super::PostInitProperties();
}

#if WITH_EDITOR
void UMissionComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);
}
#endif

void UMissionComponent::BeginPlay()
{
	Super::BeginPlay();
	
}


void UMissionComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
	if (!Initialized) return;
}

void UMissionComponent::UnTrackMission() {


}

void UMissionComponent::TrackMission(FMissionMaster MissionToStart) {


}
void UMissionComponent::BuildMissionComponent()
{

}

void UMissionComponent::Interaction_With_NPC()
{

}

void UMissionComponent::OnCountDownTimerFinished() {

}

bool UMissionComponent::IsLocallyControlled(APawn*& ControlledPawn)
{
	if (GetOwner()->IsValidLowLevel()) {
		APlayerController* PC = Cast<APlayerController>(GetOwner());
		if (PC->IsValidLowLevel() && PC->IsLocalController() && PC->IsLocalPlayerController()) {
			ControlledPawn = PC->GetPawn();
			return true;
		}
	}
	ControlledPawn = nullptr;
	return false;
}

bool UMissionComponent::IsInMisssion()
{
	return InMission;
}

bool UMissionComponent::IsOnScreen(FVector WorldLocation, FVector ExtraPading, bool HidOnScreenEdge)
{
	FVector LocWorldLocation = WorldLocation + ExtraPading + FVector(0.f, 0.f, 110.f);
	APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
	FVector2D ScreenLoction;
	bool isCan=PC->ProjectWorldLocationToScreen(LocWorldLocation, ScreenLoction, true);
	FVector2D ViewSize;
	GEngine->GameViewport->GetViewportSize(ViewSize);
	float F1 = (HidOnScreenEdge ? -25.f : 0.f) + ViewSize.X;
	float F2 = (HidOnScreenEdge ? -25.f : 0.f) + ViewSize.Y;
	bool BigBool = ScreenLoction.X > 25.f&&ScreenLoction.Y > 25.f&&ScreenLoction.X < F1&&ScreenLoction.Y < F2;
	return HidOnScreenEdge || BigBool;
}

void UMissionComponent::GetOwnerCamera(APlayerCameraManager*& OutCameraManager, USpringArmComponent*& OutSpringArm, FTransform& OutCameraTransform)
{
	APawn* Pawn = nullptr;
	if (IsLocallyControlled(Pawn)) {
		OutCameraManager = UGameplayStatics::GetPlayerCameraManager(this, 0);
		OutSpringArm=Cast<USpringArmComponent>(Pawn->GetComponentByClass(USpringArmComponent::StaticClass()));
		OutCameraTransform = FTransform(OutCameraManager->GetCameraRotation().Quaternion(),
			OutCameraManager->GetCameraLocation(), FVector::OneVector);
	}
}

void UMissionComponent::SetCompassReference()
{
	if (CompassClass->IsValidLowLevel()) {
		if(!CompassReference->IsValidLowLevel())
			CompassReference = Cast<UCompassWidget>(CreateWidget(UGameplayStatics::GetPlayerController(this, 0), CompassClass));
		if (!CompassReference->IsInViewport())
			CompassReference->AddToViewport();
	}
}

void UMissionComponent::PopulateDirections()
{
	if (CompassReference->IsValidLowLevel()) {
		for (const auto& Elem : Directions) {
			CompassReference->AddDirection(Elem, DirectionWidgetClass);
		}
	}
}

void UMissionComponent::ToggleOwnerInput(const bool& Enabled)
{
	if (Enabled) {
		UGameplayStatics::GetPlayerController(this, 0)->EnableInput(UGameplayStatics::GetPlayerController(this, 0));
	}
	else {
		UGameplayStatics::GetPlayerController(this, 0)->DisableInput(UGameplayStatics::GetPlayerController(this, 0));
	}
}

float UMissionComponent::RotateCircleToDegree(float In)
{
	if (In < 0.f) return Modulo(In + 360.f, 360.f);
	else return In;
}

void UMissionComponent::RotationToTranslation(const FRotator& RotatorA, const FRotator& RotatorB, FVector2D& OutTranslation, bool& Clockwise, bool& InRadarSight)
{
	float InDelta = 0; 
	InDelta=UMissionComponent::GetDeltaClockwise(RotateCircleToDegree(RotatorA.Yaw), RotateCircleToDegree(RotatorB.Yaw), true);
	// DEBUG_MESSAGE("InDelta:%f", InDelta)
	float CompareDelta = UMissionComponent::GetDeltaClockwise(RotateCircleToDegree(RotatorA.Yaw), RotateCircleToDegree(RotatorB.Yaw), false);
	float FOV;
	APlayerCameraManager* Temp = nullptr;
	USpringArmComponent* Temps = nullptr;
	FTransform Temt;
	GetOwnerCamera(Temp, Temps, Temt);
	if (Temp->IsValidLowLevel()) FOV = Temp->GetFOVAngle();
	else FOV = 90.f;
	if (InDelta > CompareDelta) {
		if ((CompareDelta / FOV) <= 1.f) {
			OutTranslation = FVector2D(FMath::Lerp(0.f, MaximumCompassTranslation, CompareDelta / FOV)*-1.f, 0.f);
			Clockwise = false;
			InRadarSight = true;
			return;
		}
		else {
			OutTranslation = FVector2D(0.f, 0.f);
			Clockwise = false;
			InRadarSight = false;
			return;
		}
	}
	else {
		if (InDelta / FOV <= 1.f) {
			OutTranslation = FVector2D(FMath::Lerp(0.f, MaximumCompassTranslation, InDelta / FOV), 0.f);
			Clockwise = true;
			InRadarSight = true;
			return;
		}
		else {
			OutTranslation = FVector2D(0.f, 0.f);
			Clockwise = true;
			InRadarSight = false;
			return;
		}
	}
}

float UMissionComponent::GetDeltaClockwise(const float& A, const float& b, bool ClockWise)
{
	float DeltaA = 360.f - Modulo(A,360.f) + Modulo(b, 360.f);
	float DeltaB= Modulo(b, 360.f) - Modulo(A, 360.f);
	float DeltaAb = 360.f - Modulo(b, 360.f) + Modulo(A, 360.f);
	float DeltaBb = Modulo(A, 360.f) - Modulo(b, 360.f);
	if (ClockWise) {
		if (Modulo(A, 360.f) > Modulo(b, 360.f)) return DeltaA;
		if (Modulo(A, 360.f) == Modulo(b, 360.f)) return 0.f;
		return DeltaB;
	}
	else {
		if (Modulo(A, 360.f) > Modulo(b, 360.f)) return DeltaBb;
		else if (Modulo(A, 360.f) == Modulo(b, 360.f)) return 0.f;
		else return DeltaAb;
	}
}

int32 UMissionComponent::CalculateDistance(const FVector& LocationA, const FVector& LocationB)
{
	FVector Tek(LocationA.X, LocationA.Y, 0.f);
	FVector Teg(LocationB.X, LocationB.Y, 0.f);
	return FMath::RoundToInt((Tek - Teg).Size()/UnitsPerMeter);
}

EElevationState UMissionComponent::CalculateElevation(const float& Z)
{
	APawn* Pawn=nullptr;
	IsLocallyControlled(Pawn);
	if (Pawn) {
		if (Pawn->GetActorLocation().Z + ElevationRange < Z) return EElevationState::Up;
		if (Pawn->GetActorLocation().Z - ElevationRange > Z) return EElevationState::Down;
		else return EElevationState::Same;
	}
	else return EElevationState::Select;
}

void UMissionComponent::MarkerWorldLocationToScreen(const FVector& WorldLocation, const FVector& ExtraPadding, USingleMarkerWidget* MarkerReference, FVector2D& OutScreenPosition, bool& OutOnScreen, float& OutDegree, bool& OutOnEdge)
{
	bool LocHidenOnScreenEdge = MarkerReference->TargetInfo.MarkerCustomization.HideOnScreenEdge;
	FVector2D LocalOutScreenPosition;
	float Degress=OutDegree;
	APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
	bool isonscreen = IsOnScreen(WorldLocation, ExtraPadding, LocHidenOnScreenEdge);
	if (isonscreen) {
		FVector LocTarget = WorldLocation + ExtraPadding + FVector(0.f, 3.f, 110.f);
		FVector2D GameViewSize;
		GEngine->GameViewport->GetViewportSize(GameViewSize);
		FVector LocWorldLocation, LocWorldDirection;
		PC->DeprojectScreenPositionToWorld(GameViewSize.X / 2, GameViewSize.Y / 2, LocWorldLocation, LocWorldDirection);
		FVector WL = FRotationMatrix::MakeFromX(LocTarget - LocWorldLocation - LocWorldDirection * 10.f).ToQuat().GetAxisX() + LocWorldLocation + LocWorldDirection;
		FVector2D ScreenL;
		PC->ProjectWorldLocationToScreen(WL, ScreenL, true);
		Degress = FMath::Atan2(ScreenL.X - GameViewSize.X / 2.f, ScreenL.Y - GameViewSize.Y / 2.f);
		FVector2D Normalize2 = FVector2D(ScreenL.X - GameViewSize.X / 2.f, ScreenL.Y - GameViewSize.Y / 2.f).GetSafeNormal();
		float Ap1 = FMath::Acos(FMath::Acos(Normalize2.X))*1.f*ScreenMarkerRadius;
		float Ap2 = FMath::Sin(FMath::Acos(ScreenL.Y))*(ScreenL.Y <= 0.f ? -1.f : 1.f)*ScreenMarkerRadius;
		FVector2D LocScreenPosition(
			FMath::Clamp((GameViewSize / 2.f).X + Ap1, ScreenMarkerRadius, GameViewSize.X - ScreenMarkerRadius),
			FMath::Clamp((GameViewSize / 2.f).Y + Ap2, ScreenMarkerRadius, GameViewSize.Y - ScreenMarkerRadius)
		);

		LocalOutScreenPosition = LocScreenPosition;
	}
	else {
		FVector LocalWorldLoction = WorldLocation + ExtraPadding + FVector(0.f, 0.f, 110.f);
		FVector2D LocalScreenLocation;
		bool isCan = UWidgetLayoutLibrary::ProjectWorldLocationToWidgetPosition(PC, LocalWorldLoction, LocalScreenLocation, true);
		if (isCan)
			LocalOutScreenPosition = LocalScreenLocation - MarkerReference->GetDesiredSize() / FVector2D(2.f, 2.f);
		else
			LocalOutScreenPosition = MarkerReference->GetDesiredSize()*-2.f;
	}
	OutScreenPosition = LocalOutScreenPosition;
	OutOnScreen = LocHidenOnScreenEdge?isonscreen&&LocHidenOnScreenEdge:true;
	OutDegree = Degress;
	OutOnEdge = !isonscreen;

// 	FVector ScreenPosition3D;
// 	const bool bSuccess = ProjectWorldLocationToWidgetPositionWithDistance(PlayerController, WorldLocation, ScreenPosition3D);
// 	ViewportPosition = FVector2D(ScreenPosition3D.X, ScreenPosition3D.Y);
// 	return bSuccess;

// 	if (PlayerController)
// 	{
// 		FVector PixelLocation;
// 		const bool bPlayerViewportRelative = false;
// 		const bool bProjected = PlayerController->ProjectWorldLocationToScreenWithDistance(WorldLocation, PixelLocation, bPlayerViewportRelative);
// 
// 		if (bProjected)
// 		{
// 			// Round the pixel projected value to reduce jittering due to layout rounding,
// 			// I do this before I remove scaling, because scaling is going to be applied later
// 			// in the opposite direction, so as long as we round, before inverse scale, scale should
// 			// result in more or less the same value, especially after slate does layout rounding.
// 			FVector2D ScreenPosition(FMath::RoundToInt(PixelLocation.X), FMath::RoundToInt(PixelLocation.Y));
// 
// 			FVector2D ViewportPosition2D;
// 			USlateBlueprintLibrary::ScreenToViewport(PlayerController, ScreenPosition, ViewportPosition2D);
// 			ViewportPosition.X = ViewportPosition2D.X;
// 			ViewportPosition.Y = ViewportPosition2D.Y;
// 			ViewportPosition.Z = PixelLocation.Z;
// 
// 			return true;
// 		}
// 	}
// 
// 	ViewportPosition = FVector::ZeroVector;
// 
// 	return false;

}

void UMissionComponent::UpdateCompassDirections()
{
	if (CompassReference->IsValidLowLevel()) {
		APlayerCameraManager* Temp = nullptr;
		USpringArmComponent* temp = nullptr;
		FTransform CameraTran;
		GetOwnerCamera(Temp, temp, CameraTran);
		for (int i = 0; i < CompassReference->DirectionWidgets.Num(); ++i) {
			FRotator RotationB(0.f, (float)(Directions[i].WorldRotation), 0.f);
			FVector2D Transla;
			bool outis, outcan;
			// DEBUG_MESSAGE("Directions[i].WorldRotation:%f", RotationB.Yaw)
			RotationToTranslation(CameraTran.Rotator(), RotationB, Transla, outcan, outis);
			// DEBUG_MESSAGE("Transla.X:%f  Transla.Y:%f", Transla.X, Transla.Y);
			if (outis) {
				CompassReference->DirectionWidgets[i]->SetRenderTranslation(Transla);
				if(!CompassReference->DirectionWidgets[i]->IsVisible())
					CompassReference->DirectionWidgets[i]->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
			}
			else if (CompassReference->DirectionWidgets[i]->IsVisible()) {
				CompassReference->DirectionWidgets[i]->SetVisibility(ESlateVisibility::Hidden);
			}

		}
	}
}

void UMissionComponent::UpdateCompassMarker(USingleMarkerWidget* WidgetReference, AActor* TargetActor, FVector LastKnownLocation)
{
	if (!WidgetReference->IsValidLowLevel()) return;
	APawn* Pawn = nullptr;
	if (!IsLocallyControlled(Pawn)) return;
	if (TargetActor->IsValidLowLevel()) {
		APlayerCameraManager* Temp = nullptr;
		USpringArmComponent* temp = nullptr;
		FTransform CameraTran;
		GetOwnerCamera(Temp, temp, CameraTran);

		FVector2D Transla;
		bool outis, outcan;
		RotationToTranslation(CameraTran.Rotator(), FRotationMatrix::MakeFromX(TargetActor->GetActorLocation() - Pawn->GetActorLocation()).Rotator(), Transla, outcan, outis);

		FVector2D FalseVector(outcan ? MaximumCompassTranslation : MaximumCompassTranslation * -1.f, 0.f);
		FVector2D TempVector = outis ? Transla : FalseVector;

		if (WidgetReference->TargetInfo.MarkerCustomization.HideOnCompassEdge) {
			if (outis) {
				WidgetReference->SetRenderTranslation(Transla);
				if (!WidgetReference->IsVisible())
					WidgetReference->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
			}
			else {
				if (WidgetReference->IsVisible())
					WidgetReference->SetVisibility(ESlateVisibility::Hidden);
			}
		}
		else {
			WidgetReference->SetRenderTranslation(TempVector);
		}
	}
	else {
		APlayerCameraManager* Temp = nullptr;
		USpringArmComponent* temp = nullptr;
		FTransform CameraTran;
		GetOwnerCamera(Temp, temp, CameraTran);

		FVector2D Transla;
		bool outis, outcan;
		RotationToTranslation(CameraTran.Rotator(), FRotationMatrix::MakeFromX(LastKnownLocation - Pawn->GetActorLocation()).Rotator(), Transla, outcan, outis);

		FVector2D FalseVector(outcan ? MaximumCompassTranslation : MaximumCompassTranslation * -1.f, 0.f);
		FVector2D TempVector = outis ? Transla : FalseVector;

		if (WidgetReference->TargetInfo.MarkerCustomization.HideOnCompassEdge) {
			if (outis) {
				WidgetReference->SetRenderTranslation(Transla);
				if (!WidgetReference->IsVisible())
					WidgetReference->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
			}
			else {
				if (WidgetReference->IsVisible())
					WidgetReference->SetVisibility(ESlateVisibility::Hidden);
			}
		}
		else {
			WidgetReference->SetRenderTranslation(TempVector);
		}
	}
	
}

void UMissionComponent::UpdateMarkers(EMarkerType MarkerType)
{
	if (MarkerType == EMarkerType::ScreenMarker) {
		for (USingleMarkerWidget* Elem : CompassReference->ScreenMarkers) {
			UpdateMarkerDistance(Elem, Elem->TargetInfo.NonEditTargetInfo.SelfReference, Elem->TargetInfo.NonEditTargetInfo.Location);
			UpdateScreenMarker(Elem, Elem->TargetInfo.NonEditTargetInfo.SelfReference, Elem->TargetInfo.NonEditTargetInfo.Location, Elem->TargetInfo.MarkerCustomization.MarkerExtraPadding);
		}
	}
	else if(MarkerType == EMarkerType::CompassMarker){
		for (USingleMarkerWidget* Elem : CompassReference->CompassMarkers) {
			UpdateMarkerDistance(Elem, Elem->TargetInfo.NonEditTargetInfo.SelfReference, Elem->TargetInfo.NonEditTargetInfo.Location);
			UpdateScreenMarker(Elem, Elem->TargetInfo.NonEditTargetInfo.SelfReference, Elem->TargetInfo.NonEditTargetInfo.Location, Elem->TargetInfo.MarkerCustomization.MarkerExtraPadding);
		}
	}
}

void UMissionComponent::UpdateMarkerDistance(USingleMarkerWidget* MarkerReference, AActor* TargetActor, FVector NearestLocation)
{
	APawn* Pawn = nullptr;
	if (IsLocallyControlled(Pawn)) {
		float LocDistance = 0.f;
		if (MarkerReference->IsValidLowLevel())
			LocDistance=CalculateDistance(Pawn->GetActorLocation(), TargetActor->GetActorLocation());
		else LocDistance = CalculateDistance(Pawn->GetActorLocation(), NearestLocation);
		APlayerCameraManager* Temp = nullptr;
		USpringArmComponent* temp = nullptr;
		FTransform CameraTran;
		GetOwnerCamera(Temp, temp, CameraTran);
		if (CameraTran.GetLocation().Z < 5000.f) {
			float MaxDis = MarkerReference->TargetInfo.MarkerCustomization.MaxDistanceToShowMarker;
			MarkerReference->SetVisibility(MaxDis != 0 && MaxDis >= LocDistance ? ESlateVisibility::Hidden : ESlateVisibility::Visible);
		}
		EElevationState CE;
		if (MarkerReference->IsValidLowLevel())
			CE = CalculateElevation(TargetActor->GetActorLocation().Z);
		else  CE = CalculateElevation(NearestLocation.Z);
		MarkerReference->UpdateElevation(CE);
	}
}

void UMissionComponent::UpdateScreenMarker(USingleMarkerWidget* MarkerReference, AActor* TargetActor, FVector NearestLocation, FVector ExtraPadding)
{
	if (!MarkerReference->IsValidLowLevel()||!MarkerReference->bIsVariable) return;
	FVector LocWorldLoc;
	if (TargetActor->IsValidLowLevel())
		LocWorldLoc = TargetActor->GetActorLocation();
	else LocWorldLoc = NearestLocation;
	FVector2D SP;
	bool OS, OE;
	float DE;
	MarkerWorldLocationToScreen(LocWorldLoc, ExtraPadding, MarkerReference, SP, OS, DE, OE);
	if (OS) {
		MarkerReference->Indicator->SetVisibility(OE ? ESlateVisibility::SelfHitTestInvisible : ESlateVisibility::Collapsed);
		MarkerReference->SetPositionInViewport(SP, OE);
		MarkerReference->Indicator->SetRenderTransformAngle(DE*-1.f);
	}
	else {
		MarkerReference->SetVisibility(ESlateVisibility::Hidden);
	}
}

void UMissionComponent::UpdateInteractionWidgetPosition()
{
	APawn* Pawn = nullptr;
	if (InteractionWidget->IsValidLowLevel() && IsLocallyControlled(Pawn)) {
		ACharacter* Cha = Cast<ACharacter>(Pawn);
		FVector2D SP;
		UWidgetLayoutLibrary::ProjectWorldLocationToWidgetPosition(UGameplayStatics::GetPlayerController(this, 0), Cha->GetActorLocation(), SP, true);
		InteractionWidget->SetPositionInViewport(SP - InteractionWidget->GetDesiredSize() / FVector2D(2.f, 2.f), false);
	}
}

void UMissionComponent::UpdateMarkerTargetInfo()
{
	if (CompassReference) {
		ATargetsManager* TargetsManager = UMissionSystemFL::GetTargetManager();
		for (const auto& Elem : TargetsManager->Targets) {
			for (USingleMarkerWidget* elem : CompassReference->CompassMarkers) {
				if (elem->TargetInfo.TargetUniqueName == Elem.TargetUniqueName) {
					elem->TargetInfo.NonEditTargetInfo = Elem.NonEditTargetInfo;
				}
			}

			for (USingleMarkerWidget* elem : CompassReference->ScreenMarkers) {
				if (elem->TargetInfo.TargetUniqueName == Elem.TargetUniqueName) {
					elem->TargetInfo.NonEditTargetInfo = Elem.NonEditTargetInfo;
				}
			}		
		}
	}
}

void UMissionComponent::AddObjectiveMarkers()
{
	for (const auto& Elem : CurrentObjectives) {
		if (Elem.ObjectiveClass == EObjectiveLType::SingleTarget) {
			FTargetInfo LocalTargetInfo;
			LocalTargetInfo.TargetUniqueName = Elem.ObjectiveTargets[0].TargetsUniqueName;
			LocalTargetInfo.Amount=Elem.ObjectiveTargets[0].Amount;
			LocalTargetInfo.MarkerCustomization = Elem.ObjectiveTargets[0].MarkerCustomization;
			FNonEditTarget Temp;
			Temp.ActorClass= Elem.ObjectiveTargets[0].TargetsClass;
			Temp.Location = Elem.ObjectiveTargets[0].TargetLocation;
			LocalTargetInfo.NonEditTargetInfo = Temp;
			ObjectiveMarkers.Add(CompassReference->AddMarker(LocalTargetInfo, MarkerWidgetClass));
		}
		else if (Elem.ObjectiveClass == EObjectiveLType::MultipleTargets) {
			for(const auto& elem : Elem.ObjectiveTargets){
				FTargetInfo LocalTargetInfo;
				LocalTargetInfo.TargetUniqueName = elem.TargetsUniqueName;
				LocalTargetInfo.Amount = elem.Amount;
				LocalTargetInfo.MarkerCustomization = elem.MarkerCustomization;
				FNonEditTarget Temp;
				Temp.ActorClass = elem.TargetsClass;
				Temp.Location = elem.TargetLocation;
				LocalTargetInfo.NonEditTargetInfo = Temp;
				ObjectiveMarkers.Add(CompassReference->AddMarker(LocalTargetInfo, MarkerWidgetClass));
			}
		}
	}
	UpdateMarkerTargetInfo();
}

void UMissionComponent::RemoveObjectiveMarker(const FTargetInfo& InTargetInfo)
{
	if (InTargetInfo.TargetType == ETargetType::QuestGiver	||
		InTargetInfo.TargetType == ETargetType::Enemy		||
		InTargetInfo.TargetType == ETargetType::OverlapActor||
		InTargetInfo.TargetType == ETargetType::Interactable) 
	{
		int i = 0;
		for (const USingleMarkerWidget* Elem : ObjectiveMarkers) {
			if (Elem->TargetInfo.TargetUniqueName == InTargetInfo.TargetUniqueName) {
				RemoveFromRealMarkers(Elem, true);
				ObjectiveMarkers.RemoveAt(i);
			}
			i++;
		}
	}
}

void UMissionComponent::RemoveFromRealMarkers(const USingleMarkerWidget* MarkerReference, bool Animate)
{
	if (MarkerReference->TargetInfo.MarkerCustomization.MarkerType == EMarkerType::CompassMarker) {
		int i = 0;
		for (USingleMarkerWidget* Elem : CompassReference->CompassMarkers) {
			if (Elem->TargetInfo.TargetUniqueName == MarkerReference->TargetInfo.TargetUniqueName) {
				Elem->ToggleMarker(EToggleVisibility::Visible, Animate, true);
				CompassReference->CompassMarkers.RemoveAt(i);
			}
			i++;
		}
	}
	else {
		int i = 0;
		for (USingleMarkerWidget* Elem : CompassReference->ScreenMarkers) {
			if (Elem->TargetInfo.TargetUniqueName == MarkerReference->TargetInfo.TargetUniqueName) {
				Elem->ToggleMarker(EToggleVisibility::Hidden, Animate, true);
				CompassReference->ScreenMarkers.RemoveAt(i);
			}
			i++;
		}
	}
}

void UMissionComponent::ClearAllObjectiveMarkers()
{
	for (USingleMarkerWidget* Elem : ObjectiveMarkers) {
		RemoveFromRealMarkers(Elem, true);
	}
	ObjectiveMarkers.Reset();
}

void UMissionComponent::ToggleWidgets(EToggleVisibility Visibility)
{
	if (InMissionWidget->IsValidLowLevel()) {
		InMissionWidget->ToggleMissionWidget(Visibility, false);
	}
	CompassReference->ToggleCompassVisibility(Visibility);
	for (USingleMarkerWidget* Elem : CompassReference->ScreenMarkers) {
		Elem->ToggleMarker(Visibility,true,false);
	}
}

void UMissionComponent::RemoveFromCustomMarkers(const FTargetInfo& InTargetInfo)
{
	if (InTargetInfo.MarkerCustomization.MarkerType == EMarkerType::CompassMarker) {
		int i = 0;
		for (USingleMarkerWidget* Elem : CompassReference->CompassMarkers) {
			if (Elem->TargetInfo.NonEditTargetInfo.SelfReference == InTargetInfo.NonEditTargetInfo.SelfReference) {
				Elem->ToggleMarker(EToggleVisibility::Hidden, true, true);
				CompassReference->CompassMarkers.RemoveAt(i);
			}
			++i;
		}
	}
	else if (InTargetInfo.MarkerCustomization.MarkerType == EMarkerType::ScreenMarker) {
		int i = 0;
		for (USingleMarkerWidget* Elem : CompassReference->ScreenMarkers) {
			if (Elem->TargetInfo.NonEditTargetInfo.SelfReference == InTargetInfo.NonEditTargetInfo.SelfReference) {
				Elem->ToggleMarker(EToggleVisibility::Hidden, true, true);
				CompassReference->ScreenMarkers.RemoveAt(i);
			}
			++i;
		}
	}
}

bool UMissionComponent::FollowTarget()
{
	if (TargetToFollow->IsValidLowLevel()) {
		APlayerCameraManager* Temp;
		USpringArmComponent* temp;
		FTransform CameraTra;
		GetOwnerCamera(Temp, temp, CameraTra);
		FVector StartLoc = CameraTra.GetLocation();
		FVector EndLoc = TargetToFollow->GetActorLocation() + FVector(0.f, 0.f, 20.f);
		FHitResult OutHit;
		FCollisionQueryParams Col;
		Col.AddIgnoredActor(GetOwner());
		Col.AddIgnoredActor(TargetToFollow);
		Col.bTraceComplex = false;
		bool isR=this->GetWorld()->LineTraceSingleByChannel(OutHit, StartLoc, EndLoc, ECC_Visibility, Col);
		return !DistanceWithFollowingTarget(FollowMaxDistance) || isR;
	}
	return false;
}

void UMissionComponent::OnCustomObjectiveTypes()
{
	StopFollowTarget();
	ActorsToInteract.Reset();
	for (const FObjectives& Elem : CurrentObjectives) {
		if (Elem.SpecificObjectiveType == EObjectiveType::Follow) {
			if (FindSpecialObjective(EObjectiveType::Follow).SpecialObjectivesInfo.FollowObjective.MustBeOnSight) {
				TargetToFollow=UMissionSystemFL::FindInCurrentTargets(Elem.ObjectiveTargets[0].TargetsUniqueName).NonEditTargetInfo.SelfReference;
				StartFollowTarget();
			}
		}
		else if (Elem.SpecificObjectiveType == EObjectiveType::Interact) {
			for (auto& elem : Elem.ObjectiveTargets) {
				FTargetInfo Temp;
				Temp.TargetUniqueName = elem.TargetsUniqueName;
				Temp.Amount = elem.Amount;
				Temp.MarkerCustomization = elem.MarkerCustomization;
				Temp.TargetType = ETargetType::Interactable;
				ActorsToInteract.Add(Temp);
			}
		}
	}
}

void UMissionComponent::PopulateObjectives()
{
	CurrentObjectives = CurrentMission.Sequences[CurrentSequenceIndex].Objectives;
	AddObjectiveMarkers();
	OnCustomObjectiveTypes();
}

void UMissionComponent::UpdateObjectiveProgress(const FTargetInfo& InTargetInfo)
{
	for (USingleObjectiveWidget* Elem : InMissionWidget->ObjectiveWidgets) {
		if (Elem->ObjectiveInfo.ObjectiveClass == EObjectiveLType::SingleTarget) {
			if (Elem->ObjectiveInfo.ObjectiveTargets[0].UniqueNameMatters) {
				if (Elem->ObjectiveInfo.ObjectiveTargets[0].TargetsUniqueName == InTargetInfo.TargetUniqueName) {
					Elem->UpdateAsCompleted();
					break;
				}
			}
			else if (Elem->ObjectiveInfo.ObjectiveTargets[0].TargetsClass == InTargetInfo.NonEditTargetInfo.ActorClass) {
				Elem->UpdateAsCompleted();
				break;
			}
		}
		else if (Elem->ObjectiveInfo.ObjectiveClass == EObjectiveLType::MultipleTargets) {
			for (FObjectiveMainInfo& elem : Elem->ObjectiveInfo.ObjectiveTargets) 
			{
				static int32 i = 0;
				FAssignedObjectiveTarget Temp;
				Temp.UniqueNameMatters = elem.UniqueNameMatters;
				Temp.UniqueName = InTargetInfo.TargetUniqueName;
				Temp.TargetClass = InTargetInfo.NonEditTargetInfo.ActorClass;
				Temp.Amount = InTargetInfo.Amount;
				if (elem.UniqueNameMatters) {
					if (elem.TargetsUniqueName == InTargetInfo.TargetUniqueName&&elem.Amount >= Elem->FindInTargets(Temp)) {
						while (i < InTargetInfo.Amount) {
							++i;
							Elem->AddProgress(Temp);
							if ((float)Elem->AddedAmount == Elem->MaxInProgress) {
								Elem->UpdateAsCompleted();
							}
							return;
						}
					}
				}
				else if(elem.TargetsClass==InTargetInfo.NonEditTargetInfo.ActorClass&&elem.Amount >= Elem->FindInTargets(Temp)){
					while (i < InTargetInfo.Amount) {
						++i;
						Elem->AddProgress(Temp);
						if ((float)Elem->AddedAmount == Elem->MaxInProgress) {
							Elem->UpdateAsCompleted();
						}
						return;
					}
				}
			}
		}
	}
}

bool UMissionComponent::CanSkipToNextSequence()
{
	return ObjectivesAreDone() && CurrentMission.Sequences.Num() - 1 != CurrentSequenceIndex;
}

bool UMissionComponent::ObjectivesAreDone()
{
	for (USingleObjectiveWidget* Elem : InMissionWidget->ObjectiveWidgets) {
		if (!Elem->Completed) return false;
	}
	return true;
}

bool UMissionComponent::DistanceWithFollowingTarget(float InDistance)
{
	APawn* Pawn = nullptr;
	if (IsLocallyControlled(Pawn)){
		return (TargetToFollow->GetActorLocation()-Pawn->GetActorLocation()).Size()<=InDistance;
	}
	return false;
}

void UMissionComponent::ContainsInKnownNPCs(const FTargetInfo& InTargetInfo, FDefaultNPCInfo& OutValue, bool& OutContains)
{
	FDefaultNPCInfo Temp;
	Temp.UniqueName = InTargetInfo.TargetUniqueName;
	Temp.NearestLocation = InTargetInfo.NonEditTargetInfo.Location;
	Temp.MarkerCustomization = InTargetInfo.MarkerCustomization;
	if (KnownNPCs.Num() != 0) {
		for (FDefaultNPCInfo& Elem : KnownNPCs) {
			if (InTargetInfo.TargetUniqueName == Elem.UniqueName) {
				OutContains = true;
				OutValue = Elem;
				return;
			}
		}
	}
	OutContains = false;
	OutValue = Temp;
}

bool UMissionComponent::IsNearestActorEnabled()
{
	FDefaultNPCInfo Temp;
	bool Conta;
	ContainsInKnownNPCs(NearestOverlappedNPC, Temp, Conta);
	FDefaultNPCInfo temp;
	int32 ind;
	FindInDefaultActors(Temp, temp, ind);
	return temp.Status == ENPCStatus::Enabled;
	
}

bool UMissionComponent::ContainsInActorsToInteract(const FTargetInfo& InTargetInfo)
{
	for (FTargetInfo& Elem : ActorsToInteract) {
		if (Elem.TargetUniqueName == InTargetInfo.TargetUniqueName)
			return true;
	}
	return false;
}

FObjectives UMissionComponent::FindSpecialObjective(EObjectiveType SpecialObjective)
{
	for (FObjectives& Elem : CurrentMission.Sequences[CurrentSequenceIndex].Objectives) {
		if (SpecialObjective == Elem.SpecificObjectiveType)
			return Elem;
	}
	return FObjectives();
}

void UMissionComponent::FindInDefaultActors(const FDefaultNPCInfo& InActorInfo, FDefaultNPCInfo& OutValue, int32& OutIndex)
{
	int i = 0;
	for (FDefaultNPCInfo& Elem : DefaultActors) {
		if (InActorInfo.UniqueName == Elem.UniqueName) {
			OutIndex = i;
			OutValue = Elem;
			return;
		}
		++i;
	}
	OutIndex = i;
	OutValue = FDefaultNPCInfo();
	return;
}

USingleMarkerWidget* UMissionComponent::FindDefaultMarkers(FName InUniqueName)
{
	for (USingleMarkerWidget* Elem : DefaultActorMarkers) {
		if (InUniqueName == Elem->TargetInfo.TargetUniqueName) {
			return Elem;
		}
	}
	return nullptr;
}

void UMissionComponent::FindInOverlappedNPCs(const FTargetInfo& InTargetInfo, bool& OutFounded, FTargetInfo& OutValue)
{
	for (FTargetInfo& Elem : OverlappedNPCs) {
		if (InTargetInfo.TargetUniqueName == Elem.TargetUniqueName) {
			OutFounded = true;
			OutValue = Elem;
			return;
		}
	}
	OutFounded = false;
	OutValue = FTargetInfo();
	return;
}

FTargetInfo UMissionComponent::FindNearestOverlappedNPC()
{
	APawn* Pawn = nullptr;
	FTargetInfo NearstNPCInfo;
	float FindNearstNPC = MaxNearestOverlappedNPCDistance;
	IsLocallyControlled(Pawn);
	for (FTargetInfo& Elem : OverlappedNPCs) {
		if (Elem.NonEditTargetInfo.SelfReference->IsValidLowLevel()) {
			float nea = Elem.NonEditTargetInfo.SelfReference->GetDistanceTo(Pawn);
			if (nea < FindNearstNPC) {
				FindNearstNPC = nea;
				NearstNPCInfo = Elem;
			}
		}
	}
	return NearstNPCInfo;
}

void UMissionComponent::TriggerCamera()
{
	APlayerCameraManager* Temp;
	USpringArmComponent* LocSpringArm;
	FTransform temp;
	GetOwnerCamera(Temp, LocSpringArm, temp);
	LocSpringArm->TargetArmLength=FMath::FInterpTo(LocSpringArm->TargetArmLength, CTargetArmLength,UGameplayStatics::GetWorldDeltaSeconds(this) , CInterpSpeed);
	LocSpringArm->SocketOffset = FMath::VInterpTo(LocSpringArm->SocketOffset, CTargetSocketOffset, UGameplayStatics::GetWorldDeltaSeconds(this), CInterpSpeed);
	APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
	PC->SetControlRotation(FMath::RInterpTo(PC->GetControlRotation(), CTargetRotation, UGameplayStatics::GetWorldDeltaSeconds(this), CInterpSpeed));
	bool b1 = FMath::Abs(LocSpringArm->TargetArmLength - CTargetArmLength) < 1.f;
	bool b2 = PC->GetControlRotation().Equals(CTargetRotation, 1.f);
	bool b3 = LocSpringArm->SocketOffset.Equals(CTargetSocketOffset, 1.f);
	if (b1&&b2&&b3) {
		GetWorld()->GetTimerManager().ClearTimer(CCameraTimer);
		if (CEnableInput) ToggleOwnerInput(true);
	}

}

void UMissionComponent::SetCameraDefaults()
{
	APlayerCameraManager* Temp;
	USpringArmComponent* LocSpringArm;
	FTransform temp;
	GetOwnerCamera(Temp, LocSpringArm, temp);
	DefaultArmLength = LocSpringArm->TargetArmLength;
	DefaultSocketOffset = LocSpringArm->SocketOffset;
}

void UMissionComponent::GetCameraDefaults(float& OutDefaultArmLength, FVector& OutDefaultSocketOffset)
{
	OutDefaultArmLength = DefaultArmLength;
	OutDefaultSocketOffset = DefaultSocketOffset;
}

void UMissionComponent::CreateInMissionWidget()
{
	if (InMissionClass->IsValidLowLevel()) {
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
		if (!InMissionWidget->IsValidLowLevel())
			InMissionWidget =Cast<UInMissionWidget>(CreateWidget(PC, InMissionClass));
		InMissionWidget->ConstructInMissionWidget(CurrentMission);
		if (!InMissionWidget->IsInViewport()) {
			InMissionWidget->AddToViewport();
		}
	}
}

void UMissionComponent::CreateInteractionWidget()
{
	if (InteractionClass->IsValidLowLevel()) {
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
		if (!InteractionWidget->IsValidLowLevel())
			InteractionWidget = Cast<UInteractionWidget>(CreateWidget(PC, InteractionClass));
		InteractionWidget->UpdateInteractionText(InteractionKey,*InteractionText.Find(NearestOverlappedNPC.TargetType));
		if (!InteractionWidget->IsInViewport()) {
			InteractionWidget->AddToViewport();
		}
	}
}

void UMissionComponent::CreateGlobalNotificationWidget(const float& InDisplayTime, const FText& Headline, const FText& InTopText, const bool& InSpecialArea, const FText& InSpecialAreaText, const bool& InGiveXP, const int32& InXPValue, const FLinearColor& InSpecialAreaColor, const FLinearColor& InHeadlineColor, const FLinearColor& InXPTextColor)
{
	if (GlobalNotificationClass->IsValidLowLevel()) {
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
		if (!GlobalNotificationWidget->IsValidLowLevel())
			GlobalNotificationWidget = Cast<UGlobalNotificationWidget>(CreateWidget(PC, GlobalNotificationClass));
		GlobalNotificationWidget->DisplayGlobalNotification(InDisplayTime, Headline, InTopText, InSpecialArea, InSpecialAreaText, InGiveXP, InXPValue, InSpecialAreaColor, InHeadlineColor, InXPTextColor);
		if (!GlobalNotificationWidget->IsInViewport()) {
			GlobalNotificationWidget->AddToViewport();
		}
	}
}

void UMissionComponent::CreateTimerWidget(const FTimerInfo& TimeInfo)
{
	if (TimerClass->IsValidLowLevel()) {
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
		if (!TimerWidget->IsValidLowLevel())
			TimerWidget = Cast<UTimerWidget>(CreateWidget(PC, TimerClass));
		TimerWidget->TimeInfo = TimeInfo;
		if (!TimerWidget->IsInViewport()) {
			TimerWidget->AddToViewport();
		}
	}
}

void UMissionComponent::CreateLocationObjectiveWidget(const FLocationObjectiveMaster& InLocationObjective)
{
	if (LocationObjectiveClass->IsValidLowLevel()) {
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
		if (!LocationObjectiveWidget->IsValidLowLevel())
			LocationObjectiveWidget = Cast<ULocationObjectivesWidget>(CreateWidget(PC, LocationObjectiveClass));
		LocationObjectiveWidget->UpdateLocationObjectives(InLocationObjective);
		if (!LocationObjectiveWidget->IsInViewport()) {
			LocationObjectiveWidget->AddToViewport();
		}
	}
}

void UMissionComponent::CreateSaveGameWidget()
{
	if (SaveGameClass->IsValidLowLevel()) {
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
		if (!SaveGameWidget->IsValidLowLevel())
			SaveGameWidget = Cast<USaveGameWidget>(CreateWidget(PC, SaveGameClass));
		if (!SaveGameWidget->IsInViewport()) {
			SaveGameWidget->AddToViewport();
		}
	}
}

void UMissionComponent::CreateLevelWidget()
{
	if (PlayerLevelClass->IsValidLowLevel()) {
		APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
		if (!PlayerLevelWidget->IsValidLowLevel())
			PlayerLevelWidget = Cast<UPlayerLevelWidget>(CreateWidget(PC, PlayerLevelClass));
		if (!PlayerLevelWidget->IsInViewport()) {
			PlayerLevelWidget->AddToViewport();
		}
	}
}

void UMissionComponent::RemoveFromOverlappedNPCs(const FTargetInfo& InTargetInfo)
{
	bool Founded;
	FTargetInfo Temp;
	FindInOverlappedNPCs(InTargetInfo, Founded, Temp);
	if (Founded) OverlappedNPCs.Remove(Temp);
}

void UMissionComponent::AddToOverlappedNPCs(const FTargetInfo& InTargetInfo)
{
	bool Founded;
	FTargetInfo Temp;
	FindInOverlappedNPCs(InTargetInfo, Founded, Temp);
	if (Founded) return;
	else OverlappedNPCs.Add(Temp);
	
}

void UMissionComponent::UpdateCustomDepth(const FTargetInfo& InTargetInfo, const bool& InbValue)
{
	ACharacter* Player = Cast<ACharacter>(InTargetInfo.NonEditTargetInfo.SelfReference);
	if (Player->IsValidLowLevel()) {
		Player->GetMesh()->SetRenderCustomDepth(InbValue);
		UPrimitiveComponent* Temp = Cast<UPrimitiveComponent>(Player->GetComponentByClass(UStaticMeshComponent::StaticClass()));
		if (Temp->IsValidLowLevel()) {
			Temp->SetRenderCustomDepth(InbValue);
		}
	}
}

void UMissionComponent::AddToQuestLog(const FMissionMaster& InMissionInfo)
{
	AllMissions.Add(InMissionInfo);
}

void UMissionComponent::RemoveFromQuestLog(const FMissionMaster& InMissionInfo)
{
	FMissionMaster temp = InMissionInfo;
	AllMissions.Remove(temp);
}

void UMissionComponent::SetCompletedOnQuestLog(const FMissionMaster& InMissionInfo)
{
	int32 ind;
	if(AllMissions.Find(InMissionInfo, ind))
		AllMissions[ind].MissionCategory = EQuestCategoryStatus::Completed;
}

void UMissionComponent::AddLandmark(ALandmarkMaster* InLandmark)
{

	if (Landmarks.Contains(InLandmark)) return;
	Landmarks.Add(InLandmark);
	if (CompassReference->IsValidLowLevel()) {
		CompassReference->AddLandmark(InLandmark->MarkerCustomization, MarkerWidgetClass);
	}
}

void UMissionComponent::RemoveLandmark(const ALandmarkMaster* InLandmark)
{
	int32 Inde = FindLandmarkIndex(InLandmark);
	if(Landmarks.IsValidIndex(Inde))
		Landmarks.RemoveAt(Inde);
	else return;
	if (CompassReference->Landmarks[Inde]->IsValidLowLevel()) {
		CompassReference->Landmarks[Inde]->RemoveFromParent();
		CompassReference->Landmarks.RemoveAt(Inde);
	}
}

int32 UMissionComponent::FindLandmarkIndex(const ALandmarkMaster* InLandmark)
{
	int32 i = 0;
	for (ALandmarkMaster* Elem : Landmarks) {
		if (Elem == InLandmark) {
			return i;
		}
		++i;
	}
	return -1;
}

void UMissionComponent::UpdateLandmarkMarkers()
{
	for (ALandmarkMaster* Elem : Landmarks) {
		if (Elem->IsValidLowLevel()) {
			UpdateCompassMarker(CompassReference->Landmarks[FindLandmarkIndex(Elem)], Elem, Elem->GetActorLocation());
		}
	}
}

void UMissionComponent::OnEnterToSpecialArea(const EToggleVisibility& InHighlightVisibility, const EToggleVisibility& InTextVisibility, const FLinearColor& InBrushColor, const FText& InText)
{
	CompassReference->UpdateSpecialArea(InHighlightVisibility, InTextVisibility, InBrushColor, InText);
}

void UMissionComponent::OnExitFromSpecialArea()
{

}

void UMissionComponent::StartCustomMission(const FMissionMaster& InMissionToStart)
{
	if (IsInMisssion()) return;
	InMission = true;
	CurrentSequenceIndex = 0;
	CurrentMission = InMissionToStart;
	CreateInMissionWidget();
	InMissionWidget->ToggleMissionWidget(EToggleVisibility::Visible, false);
	PopulateObjectives();
	SaveGameOnComponent(false);
}

void UMissionComponent::LoadSavedGameForComponent()
{
	if (IsNewGame) {
		StartMissionFromDataTable(StartupMission);
		SaveGameOnComponent(false);
	}
	else {
		FSavedMissionComponent Temp = UGameKitFL::GetMissionComponentSaveData();
		PlayerLevel = UGameKitFL::GetPlayerSaveData().PlayerLevel;
		DiscoveredLocations = Temp.DiscoveredLocations;
		AllMissions = Temp.AllMissions;
		DefaultActors = Temp.DefaultNPCs;
		KnownNPCs = Temp.KnownNPCs;
		if (Temp.WasInMission)
			StartCustomMission(Temp.LastMission);
	}
}

void UMissionComponent::SaveGameOnComponent(bool DisplaySaveWidget)
{
	if (DisplaySaveWidget) {
		CreateSaveGameWidget();
		SaveGameWidget->ShowSaveWidget(3.f, FText::FromString("S A V I N G..."));
		FSavedMissionComponent Temp;
		Temp.WasInMission = InMission;
		Temp.LastMission = CurrentMission;
		Temp.DiscoveredLocations = DiscoveredLocations;
		Temp.AllMissions = AllMissions;
		Temp.DefaultNPCs = DefaultActors;
		Temp.KnownNPCs = KnownNPCs;
		UGameKitFL::UpdateMissionComponentSaveData(Temp);
		APawn* Pawn = nullptr;
		IsLocallyControlled(Pawn);
		FSavedPlayerInfo temp;
		temp.PlayerTransform = Pawn->GetActorTransform();
		temp.ControlRotation = Pawn->GetBaseAimRotation();
		temp.PlayerLevel = PlayerLevel;
		UGameKitFL::UpdatePlayerSaveData(temp);
	}
}

bool UMissionComponent::RestartMission()
{
	if (CurrentMission.OnMissionFinished.RestartOptions.RestartOnFail) {
		if (GetWorld()->GetNetMode() == NM_Standalone) {
			UGameplayStatics::GetGameMode(this)->ResetLevel();
			APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
			UGameplayStatics::GetGameMode(this)->RestartPlayerAtTransform(PC,FTransform(FRotator::ZeroRotator, CurrentMission.OnMissionFinished.RestartOptions.RestartLocation));
			InMissionWidget->ResetInMissionWidget();
			StartCustomMission(CurrentMission);
			return true;
		}
	}
	return false;
}

void UMissionComponent::StartMissionFromDataTable(const FDataTableRowHandle& InMissionToStart)
{
	if (InMissionToStart.DataTable->IsValidLowLevel()) {
		if (IsInMisssion()) return;
		InMission = true;
		APawn* Pawn=nullptr;
		if (IsLocallyControlled(Pawn)) {
			CurrentSequenceIndex = 0;
			if (InMissionToStart.DataTable->IsValidLowLevel()) {
				FMissionMaster* Temp=InMissionToStart.DataTable->FindRow<FMissionMaster>(InMissionToStart.RowName,FString("UMissionComponent::StartMissionFromDataTable"));
				if (Temp) {
					CurrentMission = *Temp;
					AddToQuestLog(CurrentMission);
					CreateInMissionWidget();
					InMissionWidget->ToggleMissionWidget(EToggleVisibility::Visible, false);
					PopulateObjectives();
				}
			}
		}
	}
}

float UMissionComponent::Modulo(float A, float B) {
	return (B != 0.f) ? FMath::Fmod(A, B) : 0.f;
}